; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -mtriple=aarch64-linux-gnu -passes=typepromotion,verify -S %s -o - | FileCheck %s

target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"

%struct.bar = type { %struct.foo }
%struct.foo = type { ptr }
%struct.wobble = type { ptr }
%struct.zot = type <{ %struct.wobble, ptr, ptr, i8, [7 x i8] }>

@global = external global %struct.bar, align 8

define i64 @zext_trunc_i8_i16_i32_i64() {
; CHECK-LABEL: @zext_trunc_i8_i16_i32_i64(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[VAR:%.*]] = load ptr, ptr @global, align 8
; CHECK-NEXT:    br label [[PREHEADER:%.*]]
; CHECK:       preheader:
; CHECK-NEXT:    br label [[HEADER:%.*]]
; CHECK:       header:
; CHECK-NEXT:    [[VAR4:%.*]] = phi i64 [ [[VAR30:%.*]], [[LATCH:%.*]] ], [ 0, [[PREHEADER]] ]
; CHECK-NEXT:    [[VAR5:%.*]] = phi ptr [ [[VAR38:%.*]], [[LATCH]] ], [ [[VAR]], [[PREHEADER]] ]
; CHECK-NEXT:    [[VAR6:%.*]] = phi i32 [ [[VAR21:%.*]], [[LATCH]] ], [ 0, [[PREHEADER]] ]
; CHECK-NEXT:    br label [[MIDBLOCK:%.*]]
; CHECK:       midblock:
; CHECK-NEXT:    [[VAR15:%.*]] = getelementptr inbounds [[STRUCT_WOBBLE:%.*]], ptr [[VAR5]], i64 9
; CHECK-NEXT:    [[VAR17:%.*]] = load i16, ptr [[VAR15]], align 8
; CHECK-NEXT:    [[TMP0:%.*]] = zext i16 [[VAR17]] to i32
; CHECK-NEXT:    [[VAR18:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT:    [[VAR19:%.*]] = lshr i32 [[TMP0]], 8
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[VAR19]], 255
; CHECK-NEXT:    [[VAR21]] = select i1 [[VAR18]], i32 [[VAR6]], i32 [[TMP1]]
; CHECK-NEXT:    [[VAR23:%.*]] = shl nuw i32 [[VAR21]], 8
; CHECK-NEXT:    [[VAR24:%.*]] = and i32 [[TMP0]], 255
; CHECK-NEXT:    [[VAR25:%.*]] = or i32 [[VAR23]], [[VAR24]]
; CHECK-NEXT:    [[VAR26:%.*]] = select i1 [[VAR18]], i64 0, i64 65536
; CHECK-NEXT:    [[VAR27:%.*]] = zext i32 [[VAR25]] to i64
; CHECK-NEXT:    [[VAR28:%.*]] = and i64 [[VAR4]], -4294967296
; CHECK-NEXT:    [[VAR29:%.*]] = or i64 [[VAR26]], [[VAR28]]
; CHECK-NEXT:    [[VAR30]] = or i64 [[VAR29]], [[VAR27]]
; CHECK-NEXT:    br label [[LATCH]]
; CHECK:       latch:
; CHECK-NEXT:    [[VAR34:%.*]] = getelementptr inbounds [[STRUCT_WOBBLE]], ptr [[VAR5]], i64 1, i32 0
; CHECK-NEXT:    [[VAR35:%.*]] = load ptr, ptr [[VAR34]], align 8
; CHECK-NEXT:    [[VAR36:%.*]] = icmp eq ptr [[VAR35]], null
; CHECK-NEXT:    [[VAR37:%.*]] = getelementptr inbounds [[STRUCT_ZOT:%.*]], ptr [[VAR35]], i64 0, i32 2
; CHECK-NEXT:    [[VAR38]] = load ptr, ptr [[VAR37]], align 8
; CHECK-NEXT:    br i1 [[VAR36]], label [[EXIT:%.*]], label [[HEADER]]
; CHECK:       exit:
; CHECK-NEXT:    ret i64 [[VAR30]]
;
entry:
  %var = load ptr, ptr @global, align 8
  br label %preheader

preheader:
  br label %header

header:                                              ; preds = %bb63, %bb
  %var4 = phi i64 [ %var30, %latch ], [ 0, %preheader ]
  %var5 = phi ptr [ %var38, %latch ], [ %var, %preheader ]
  %var6 = phi i8 [ %var21, %latch ], [ 0, %preheader ]
  br label %midblock

midblock:                                             ; preds = %bb9
  %var15 = getelementptr inbounds %struct.wobble, ptr %var5, i64 9
  %var17 = load i16, ptr %var15, align 8
  %var18 = icmp eq i16 %var17, 0
  %var19 = lshr i16 %var17, 8
  %var20 = trunc i16 %var19 to i8
  %var21 = select i1 %var18, i8 %var6, i8 %var20
  %var22 = zext i8 %var21 to i16
  %var23 = shl nuw i16 %var22, 8
  %var24 = and i16 %var17, 255
  %var25 = or i16 %var23, %var24
  %var26 = select i1 %var18, i64 0, i64 65536
  %var27 = zext i16 %var25 to i64
  %var28 = and i64 %var4, -4294967296
  %var29 = or i64 %var26, %var28
  %var30 = or i64 %var29, %var27
  br label %latch

latch:                                             ; preds = %bb14, %bb9
  %var34 = getelementptr inbounds %struct.wobble, ptr %var5, i64 1, i32 0
  %var35 = load ptr, ptr %var34, align 8
  %var36 = icmp eq ptr %var35, null
  %var37 = getelementptr inbounds %struct.zot, ptr %var35, i64 0, i32 2
  %var38 = load ptr, ptr %var37, align 8
  br i1 %var36, label %exit, label %header

exit:
  ret i64 %var30
}

define i64 @with_undef() {
; CHECK-LABEL: @with_undef(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[VAR:%.*]] = load ptr, ptr @global, align 8
; CHECK-NEXT:    br label [[PREHEADER:%.*]]
; CHECK:       preheader:
; CHECK-NEXT:    br label [[HEADER:%.*]]
; CHECK:       header:
; CHECK-NEXT:    [[VAR4:%.*]] = phi i64 [ [[VAR30:%.*]], [[LATCH:%.*]] ], [ undef, [[PREHEADER]] ]
; CHECK-NEXT:    [[VAR5:%.*]] = phi ptr [ [[VAR38:%.*]], [[LATCH]] ], [ [[VAR]], [[PREHEADER]] ]
; CHECK-NEXT:    [[VAR6:%.*]] = phi i32 [ [[VAR21:%.*]], [[LATCH]] ], [ 0, [[PREHEADER]] ]
; CHECK-NEXT:    br label [[MIDBLOCK:%.*]]
; CHECK:       midblock:
; CHECK-NEXT:    [[VAR15:%.*]] = getelementptr inbounds [[STRUCT_WOBBLE:%.*]], ptr [[VAR5]], i64 9
; CHECK-NEXT:    [[VAR17:%.*]] = load i16, ptr [[VAR15]], align 8
; CHECK-NEXT:    [[TMP0:%.*]] = zext i16 [[VAR17]] to i32
; CHECK-NEXT:    [[VAR18:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT:    [[VAR19:%.*]] = lshr i32 [[TMP0]], 8
; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[VAR19]], 255
; CHECK-NEXT:    [[VAR21]] = select i1 [[VAR18]], i32 [[VAR6]], i32 [[TMP1]]
; CHECK-NEXT:    [[VAR23:%.*]] = shl nuw i32 [[VAR21]], 8
; CHECK-NEXT:    [[VAR24:%.*]] = and i32 [[TMP0]], 255
; CHECK-NEXT:    [[VAR25:%.*]] = or i32 [[VAR23]], [[VAR24]]
; CHECK-NEXT:    [[VAR26:%.*]] = select i1 [[VAR18]], i64 0, i64 65536
; CHECK-NEXT:    [[VAR27:%.*]] = zext i32 [[VAR25]] to i64
; CHECK-NEXT:    [[VAR28:%.*]] = and i64 [[VAR4]], -4294967296
; CHECK-NEXT:    [[VAR29:%.*]] = or i64 [[VAR26]], [[VAR28]]
; CHECK-NEXT:    [[VAR30]] = or i64 [[VAR29]], [[VAR27]]
; CHECK-NEXT:    br label [[LATCH]]
; CHECK:       latch:
; CHECK-NEXT:    [[VAR34:%.*]] = getelementptr inbounds [[STRUCT_WOBBLE]], ptr [[VAR5]], i64 1, i32 0
; CHECK-NEXT:    [[VAR35:%.*]] = load ptr, ptr [[VAR34]], align 8
; CHECK-NEXT:    [[VAR36:%.*]] = icmp eq ptr [[VAR35]], null
; CHECK-NEXT:    [[VAR37:%.*]] = getelementptr inbounds [[STRUCT_ZOT:%.*]], ptr [[VAR35]], i64 0, i32 2
; CHECK-NEXT:    [[VAR38]] = load ptr, ptr [[VAR37]], align 8
; CHECK-NEXT:    br i1 [[VAR36]], label [[EXIT:%.*]], label [[HEADER]]
; CHECK:       exit:
; CHECK-NEXT:    ret i64 [[VAR30]]
;
entry:
  %var = load ptr, ptr @global, align 8
  br label %preheader

preheader:
  br label %header

header:                                              ; preds = %bb63, %bb
  %var4 = phi i64 [ %var30, %latch ], [ undef, %preheader ]
  %var5 = phi ptr [ %var38, %latch ], [ %var, %preheader ]
  %var6 = phi i8 [ %var21, %latch ], [ undef, %preheader ]
  br label %midblock

midblock:                                             ; preds = %bb9
  %var15 = getelementptr inbounds %struct.wobble, ptr %var5, i64 9
  %var17 = load i16, ptr %var15, align 8
  %var18 = icmp eq i16 %var17, 0
  %var19 = lshr i16 %var17, 8
  %var20 = trunc i16 %var19 to i8
  %var21 = select i1 %var18, i8 %var6, i8 %var20
  %var22 = zext i8 %var21 to i16
  %var23 = shl nuw i16 %var22, 8
  %var24 = and i16 %var17, 255
  %var25 = or i16 %var23, %var24
  %var26 = select i1 %var18, i64 0, i64 65536
  %var27 = zext i16 %var25 to i64
  %var28 = and i64 %var4, -4294967296
  %var29 = or i64 %var26, %var28
  %var30 = or i64 %var29, %var27
  br label %latch

latch:                                             ; preds = %bb14, %bb9
  %var34 = getelementptr inbounds %struct.wobble, ptr %var5, i64 1, i32 0
  %var35 = load ptr, ptr %var34, align 8
  %var36 = icmp eq ptr %var35, null
  %var37 = getelementptr inbounds %struct.zot, ptr %var35, i64 0, i32 2
  %var38 = load ptr, ptr %var37, align 8
  br i1 %var36, label %exit, label %header

exit:
  ret i64 %var30
}

; Check the case don't crash due to zext source type bitwidth
; larger than dest type bitwidth.
define i1 @pr58843(i8 %arg) {
; CHECK-LABEL: @pr58843(
; CHECK-NEXT:    [[EXT1:%.*]] = zext i8 [[ARG:%.*]] to i64
; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[EXT1]], 7
; CHECK-NEXT:    [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[TMP2]], 0
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %ext1 = zext i8 %arg to i64
  %trunc = trunc i64 %ext1 to i3
  %ext2 = zext i3 %trunc to i8
  %cmp = icmp ne i8 %ext2, 0
  ret i1 %cmp
}

; Check the case don't crash due to xor two op have different
; types
define i1 @pr59554(i8 %arg) {
; CHECK-LABEL: @pr59554(
; CHECK-NEXT:    [[ARG_EXT:%.*]] = zext i8 [[ARG:%.*]] to i64
; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[ARG_EXT]], 7
; CHECK-NEXT:    [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
; CHECK-NEXT:    [[SWITCH_TABLEIDX:%.*]] = xor i32 [[TMP2]], 1
; CHECK-NEXT:    [[SWITCH_LOBIT:%.*]] = icmp ne i32 [[TMP2]], 0
; CHECK-NEXT:    ret i1 [[SWITCH_LOBIT]]
;
  %arg.ext = zext i8 %arg to i64
  %trunc = trunc i64 %arg.ext to i3
  %switch.tableidx = xor i3 %trunc, 1
  %switch.maskindex = zext i3 %trunc to i8
  %switch.lobit = icmp ne i8 %switch.maskindex, 0
  ret i1 %switch.lobit
}
